<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
    <title>Custom TileLayer | Sample | ArcGIS API for JavaScript 4.18</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css"/>

    <style>
        html,
        body,
        #viewDiv {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
        }
    </style>

    <script src="https://js.arcgis.com/4.18/"></script>

    <script>
        require([
            "esri/Map","esri/request","esri/Color","esri/views/SceneView","esri/widgets/LayerList","esri/layers/BaseTileLayer"
        ], function (Map,esriRequest,Color,SceneView,LayerList,BaseTileLayer) {
            // *******************************************************
            //自定义瓦片图层类代码
            //创建 BaseTileLayer 的子类
            // *******************************************************

            var TintLayer = BaseTileLayer.createSubclass({
                properties: {
                    urlTemplate: null,
                    tint: {
                        value: null,
                        type: Color
                    }
                },

                //生成给定级别、行和列的 tile url
                getTileUrl: function (level, row, col) {
                    return this.urlTemplate
                        .replace("{z}", level)
                        .replace("{x}", col)
                        .replace("{y}", row);
                },

                // 此方法获取指定级别和大小的切片
                // 覆盖此方法以处理从服务器返回的数据。
                fetchTile: function (level, row, col, options) {
                    // 调用 getTileUrl() 方法为 LayerView 提供的给定级别、行和列构造图块的 URL
                    var url = this.getTileUrl(level, row, col);

                    //基于生成的 url 请求图块信号选项确保过时的请求被中止
                    return esriRequest(url, {
                        responseType: "image",
                        signal: options && options.signal
                    }).then(
                        function (response) {
                            //当 esri 请求成功解析时，从响应中获取图像
                            var image = response.data;
                            var width = this.tileInfo.size[0];
                            var height = this.tileInfo.size[0];

                            //创建具有 2D 渲染上下文的画布
                            var canvas = document.createElement("canvas");
                            var context = canvas.getContext("2d");
                            canvas.width = width;
                            canvas.height = height;

                            //将应用程序提供的色调颜色应用到画布上
                            if (this.tint) {
                                //获取 rgba 形式的 CSS 颜色字符串，表示 tint Color 实例。
                                context.fillStyle = this.tint.toCss();
                                context.fillRect(0, 0, width, height);

                                //在画布和茎图块之间应用“差异”混合操作。差异混合操作从顶层（瓦片）中减去底层（画布），或者相反，总是得到一个正值。
                                context.globalCompositeOperation = "difference";
                            }

                            //将混合图像绘制到画布上。
                            context.drawImage(image, 0, 0, width, height);

                            return canvas;
                        }.bind(this)
                    );
                }
            });


            var stamenTileLayer = new TintLayer({
                urlTemplate:
                    "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png",
                tint: new Color("#004FBB"),
                title: "Stamen Toner"
            });

            var map = new Map({
                layers: [stamenTileLayer]
            });

            var view = new SceneView({
                container: "viewDiv",
                map: map,
                center: [0, 30],
                zoom: 3
            });

            var layerList = new LayerList({
                view: view
            });
            view.ui.add(layerList, "top-right");
        });
    </script>
</head>

<body>
<div id="viewDiv"></div>
</body>
</html>
